// Turn on the lightweight syntax
#light

/// <summary>
/// Namespace with types for building abstract reprezentation (AR) of Modelica model.
/// </summary>
/// <remarks>
/// AR of the model has tree structure. Nodes are classes derived from
/// ModelicaClass which contains information about their descendants
/// in List<ModelicaClass> (it's C# list, not F# - so in F# we use ResizeArray).
/// </remarks>
namespace Modelica.ModelicaTypes

    open System    
    open System.Collections.Generic   
    open Modelica.Annotations
    open OmcSocketClient
         
    /// <summary>
    /// Root object of the Modelica type system object representation hierarchy. </summary>
    type IModelicaTypeSystemBase =         
        abstract member IsPrimitive : bool
        abstract member ToString : string
                    
    type Variability =
        | Constant
        | Discrete
        | Parameter
        | None
        
    type Visibility = 
        | Protected
        | Public
    
    /// <summary>
    /// Base class for constructed types - classes, (maybe also enums???). 
    /// A little HACK to achieve cross reference between ModelicaClass and Component </summary>
    type ModelicaConstructedType() = 
        interface IModelicaTypeSystemBase with
            member x.IsPrimitive =
                false
            member x.ToString =
                "ModelicaConstructedType"
                        
    type Component(compType:IModelicaTypeSystemBase,compName:string,comm:string,place:Placement) =
        let mutable componentType = compType
        let mutable compName = compName
        let mutable compPlacement = place
        let mutable final = false
        let mutable flow = false
        let mutable visibility = Visibility.Public
        let mutable replaceable = false
        let mutable variability = Variability.None
        let mutable comment = comm
        // HACK
        let mutable containerClass = new ModelicaConstructedType()
        
        /// <summary>
        /// Type of the component - when displaying icon, downcast to 
        /// ModelicaClass and the access the Icon property.
        /// </summary>
        member x.Type 
            with get() = componentType
            and  set(v) = componentType <- v
            
        member x.Name
            with get() = compName
            and  set(v) = compName <- v
            
        member x.Placement
            with get() = compPlacement
            and  set(v) = compPlacement <- v
            
        member x.Final
            with get() = final
            and  set(v) = final <- v
    
        member x.Flow 
            with get() = flow
            and  set(v) = flow <- v
            
        member x.Visbility
            with get() = visibility
            and  set(v) = visibility <- v
            
        member x.Replaceable
            with get() = replaceable
            and  set(v) = replaceable <- v
            
        member x.Variability
            with get() = variability
            and  set(v) = variability <- v
            
        member x.Comment
            with get() = comment
            and  set(v) = comment <- v
            
        member x.ContainerClass
            with get() = containerClass
            and  set(v) = containerClass <- v
    
        /// <summary>
        /// Call this to determine, whether the icon of component sholud be displayed. </summary>
        member x.IsIconVisible =
            (visibility = Visibility.Protected) or (compPlacement = null) or (x.Type.IsPrimitive)
    
        
    /// <summary>
    /// Base class for all elements in abstract reprezentation of Modelica model.</summary>
    /// <param name="fullName">
    /// Qualified name of the class to be created.</param>
    /// <param name="diagrma">
    /// Diagram of the class</param>
    /// <param name="icon">
    /// Icon of the class</param>
    type ModelicaClass(fullName:string,diagram:Diagram,icon:Icon) =        
        inherit ModelicaConstructedType()      
        
        /// <summary> Prefix of the full qualified name, parsed from the constructor parameter. </summary>
        let mutable namePath =             
            let namePathIndex = fullName.LastIndexOf(".",fullName.Length)
            match namePathIndex with
                | -1 -> ""
                | _ -> fullName.Substring(0,namePathIndex)
        /// <summary> Actual name of the class, parsed from the constructor parameter. </summary>
        let mutable name = 
            let namePathIndex = fullName.LastIndexOf(".",fullName.Length)
            match namePathIndex with
                | -1 -> fullName
                | _ -> fullName.Substring(namePathIndex+1,fullName.Length-namePathIndex-1)
        /// <summary> Icon of the clas  </summary>
        let mutable iconDesc:Icon = icon
        /// <summary> Diagram of the class  </summary>
        let mutable diagramDesc:Diagram = diagram        
        /// <summary> Elements contained in this particular class, initially empty ResizeArray  </summary>
        let mutable containedClasses:ResizeArray<ModelicaClass> = new ResizeArray<ModelicaClass>()
        /// <summary>List of base classes from which the class derives </summary>
        let mutable baseClasses:ResizeArray<ModelicaClass> = new ResizeArray<ModelicaClass>()
        /// <summary> List of the components of the class </summary>
        let mutable components:ResizeArray<Component> = new ResizeArray<Component>()
        
        /// <summary> Help string for the class in Modelica model </summary>
        let mutable helpString = String.Empty

        /// <summary> Actual name of the class </summary>
        member x.Name
            with get() = name
            and  set(v) = name <- v
        
        /// <summary> Qualified name of the class. Change of the qualified name also affects actual name. </summary>
        member x.QualifiedName
            with get() = 
                match namePath with
                    | ""  -> x.Name
                    | _ -> namePath + "." + x.Name
            and  set(v:string) =                 
                let namePathIndex = v.LastIndexOf(".",fullName.Length) 
                match namePathIndex with
                    | -1 -> namePath <- ""; name <- v
                    | _ -> namePath <- v.Substring(0,namePathIndex); name <- v.Substring(namePathIndex+1,fullName.Length-1)
        
        /// <summary> Icon of the clas  </summary>
        member x.Icon
            with get() = iconDesc
            and  set(v) = iconDesc <- v 
        
        /// <summary> Diagram of the class  </summary>
        member x.Diagram
            with get() = diagramDesc
            and  set(v) = diagramDesc <- v
                  
        /// <summary> Elements contained in this particular class  </summary>
        member x.ContainedClasses
            with get() = containedClasses
            and  set(v) = containedClasses <- v
        /// <summary> Components contained in the class  </summary>
        member x.Components
            with get() = components
            and  set(v) = components <- v
        
        /// <summary> Base classes from which the class is derived.  </summary>
        member x.BaseClasses
            with get() = baseClasses
            and  set(v) = baseClasses <- v
        
        /// <summary> Help string for the class in Modelica model </summary>
        member x.HelpString
            with get() = helpString
            and  set(v) = helpString <- v                
        
        /// <summary> ToString method. </summary>
        override x.ToString() =
            x.QualifiedName

        /// <summary> Constructor without parameters. Creates ModelicaClass with name "DefaultName and empty icon and diagram structures"  </summary>
        new() = ModelicaClass("DefaultName", new Diagram() , new Icon())
                     
    /// <summary>
    /// Class for model elements in abstract reprezentation of Modelica model</summary>
    /// <param name="fullName">
    /// Qualified name of the class to be created.</param>
    /// <param name="diagrma">
    /// Diagram of the class</param>
    /// <param name="icon">
    /// Icon of the class</param>
    type ModelicaModel( fullName:string, diagram:Diagram, icon:Icon ) = 
        inherit ModelicaClass( fullName, diagram, icon)   
        
    /// <summary>
    /// Class for package elements in abstract reprezentation of Modelica model</summary>
    /// <param name="fullName">
    /// Qualified name of the class to be created.</param>
    /// <param name="diagrma">
    /// Diagram of the class</param>
    /// <param name="icon">
    /// Icon of the class</param>
    type ModelicaPackage(fullName:string,diagram:Diagram,icon:Icon ) = 
        inherit ModelicaClass(fullName, diagram, icon)
   
    /// <summary>
    /// Class for reocrd elements in abstract reprezentation of Modelica model</summary>
    /// <param name="fullName">
    /// Qualified name of the class to be created.</param>
    /// <param name="diagrma">
    /// Diagram of the class</param>
    /// <param name="icon">
    /// Icon of the class</param>
    type ModelicaRecord(fullName:string,diagram:Diagram,icon:Icon ) = 
        inherit ModelicaClass(fullName, diagram, icon)

    /// <summary>
    /// Class for connector elements in abstract reprezentation of Modelica model</summary>
    /// <param name="fullName">
    /// Qualified name of the class to be created.</param>
    /// <param name="diagrma">
    /// Diagram of the class</param>
    /// <param name="icon">
    /// Icon of the class</param>            
    type ModelicaConnector(fullName:string,diagram:Diagram,icon:Icon ) =
        inherit ModelicaClass(fullName, diagram, icon)
            
    /// <summary>
    /// Class for type elements in abstract reprezentation of Modelica model</summary>
    /// <param name="fullName">
    /// Qualified name of the class to be created.</param>
    /// <param name="diagrma">
    /// Diagram of the class</param>
    /// <param name="icon">
    /// Icon of the class</param>
    type ModelicaType(fullName:string,diagram:Diagram,icon:Icon ) =
        inherit ModelicaClass(fullName, diagram, icon) 
            
    /// <summary>
    /// Class for block elements in abstract reprezentation of Modelica model</summary>
    /// <param name="fullName">
    /// Qualified name of the class to be created.</param>
    /// <param name="diagrma">
    /// Diagram of the class</param>
    /// <param name="icon">
    /// Icon of the class</param>
    type ModelicaBlock(fullName:string,diagram:Diagram,icon:Icon ) =
        inherit ModelicaClass(fullName, diagram, icon)
            
    /// <summary>
    /// Class for function elements in abstract reprezentation of Modelica model</summary>
    /// <param name="fullName">
    /// Qualified name of the class to be created.</param>
    /// <param name="diagrma">
    /// Diagram of the class</param>
    /// <param name="icon">
    /// Icon of the class</param>
    type ModelicaFunction(fullName:string,diagram:Diagram,icon:Icon ) =
        inherit ModelicaClass(fullName, diagram, icon)        
            
    type ModelicaBoolean() =
        interface IModelicaTypeSystemBase with
            member x.IsPrimitive =
                true
            member x.ToString = "Boolean"
                                                
    type ModelicaInteger() =
        interface IModelicaTypeSystemBase with
            member x.IsPrimitive =
                true
            member x.ToString = "Integer"
                
    type ModelicaReal() =
        interface IModelicaTypeSystemBase with
            member x.IsPrimitive =
                true
            member x.ToString = "Real"
                    
    type ModelicaString() =
        interface IModelicaTypeSystemBase with
            member x.IsPrimitive =
                true
            member x.ToString = "String"
                
    type ModelicaEnum() =
        interface IModelicaTypeSystemBase with
            member x.IsPrimitive =
                true
            member x.ToString = "Enum"
                    
    type ClassRegister() = 
        
        static let existingClasses = new Dictionary<string,ModelicaClass>()
        
        static member ClassWasCreated( className:string ) = 
            existingClasses.ContainsKey( className )
            
        static member AddCreatedClass( newClass:ModelicaClass ) =
            existingClasses.Add( newClass.QualifiedName,newClass )
            
        static member DeleteCreatedClass( deletedClass:ModelicaClass ) = 
            existingClasses.Remove( deletedClass.QualifiedName )
            
        static member GetCreatedClass( className:string ) = 
            existingClasses.Item( className )
            
            